# -*- coding: utf-8 -*-
"""
心理咨询师服务系统 - 辅助函数
"""

import re
import string
import secrets
import unicodedata
from datetime import datetime, date
from typing import Optional, Union


def generate_random_string(length: int = 32, include_symbols: bool = False) -> str:
    """生成随机字符串
    
    Args:
        length: 字符串长度
        include_symbols: 是否包含符号
    
    Returns:
        随机字符串
    """
    alphabet = string.ascii_letters + string.digits
    if include_symbols:
        alphabet += string.punctuation
    
    return ''.join(secrets.choice(alphabet) for _ in range(length))


def validate_email(email: str) -> bool:
    """验证邮箱格式
    
    Args:
        email: 邮箱地址
    
    Returns:
        是否有效
    """
    if not email or not isinstance(email, str):
        return False
    
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return bool(re.match(pattern, email.strip().lower()))


def validate_phone(phone: str) -> bool:
    """验证手机号格式
    
    Args:
        phone: 手机号
    
    Returns:
        是否有效
    """
    if not phone or not isinstance(phone, str):
        return False
    
    # 中国大陆手机号格式
    pattern = r'^1[3-9]\d{9}$'
    return bool(re.match(pattern, phone.strip()))


def format_datetime(dt: Union[datetime, date, str], format_str: str = '%Y-%m-%d %H:%M:%S') -> str:
    """格式化日期时间
    
    Args:
        dt: 日期时间对象或字符串
        format_str: 格式字符串
    
    Returns:
        格式化后的字符串
    """
    if isinstance(dt, str):
        return dt
    
    if isinstance(dt, date) and not isinstance(dt, datetime):
        dt = datetime.combine(dt, datetime.min.time())
    
    if isinstance(dt, datetime):
        return dt.strftime(format_str)
    
    return str(dt)


def calculate_age(birth_date: Union[date, str]) -> Optional[int]:
    """计算年龄
    
    Args:
        birth_date: 出生日期
    
    Returns:
        年龄
    """
    if isinstance(birth_date, str):
        try:
            birth_date = datetime.strptime(birth_date, '%Y-%m-%d').date()
        except ValueError:
            return None
    
    if not isinstance(birth_date, date):
        return None
    
    today = date.today()
    age = today.year - birth_date.year
    
    # 检查是否还没过生日
    if today.month < birth_date.month or (today.month == birth_date.month and today.day < birth_date.day):
        age -= 1
    
    return age if age >= 0 else None


def sanitize_filename(filename: str, max_length: int = 255) -> str:
    """清理文件名
    
    Args:
        filename: 原始文件名
        max_length: 最大长度
    
    Returns:
        清理后的文件名
    """
    if not filename:
        return 'unnamed_file'
    
    # 移除或替换不安全的字符
    filename = re.sub(r'[<>:"/\\|?*]', '_', filename)
    
    # 移除控制字符
    filename = ''.join(char for char in filename if unicodedata.category(char)[0] != 'C')
    
    # 移除前后空格和点
    filename = filename.strip(' .')
    
    # 限制长度
    if len(filename) > max_length:
        name, ext = filename.rsplit('.', 1) if '.' in filename else (filename, '')
        max_name_length = max_length - len(ext) - 1 if ext else max_length
        filename = name[:max_name_length] + ('.' + ext if ext else '')
    
    return filename or 'unnamed_file'


def truncate_text(text: str, max_length: int = 100, suffix: str = '...') -> str:
    """截断文本
    
    Args:
        text: 原始文本
        max_length: 最大长度
        suffix: 后缀
    
    Returns:
        截断后的文本
    """
    if not text or len(text) <= max_length:
        return text
    
    return text[:max_length - len(suffix)] + suffix


def normalize_string(text: str) -> str:
    """标准化字符串
    
    Args:
        text: 原始字符串
    
    Returns:
        标准化后的字符串
    """
    if not text:
        return ''
    
    # 移除前后空格
    text = text.strip()
    
    # 标准化Unicode
    text = unicodedata.normalize('NFKC', text)
    
    # 移除多余的空格
    text = re.sub(r'\s+', ' ', text)
    
    return text


def format_duration(seconds: Union[int, float, None]) -> str:
    """格式化时长
    
    Args:
        seconds: 秒数
    
    Returns:
        格式化后的时长字符串
    """
    if seconds is None:
        return '未知'
    
    try:
        seconds = int(seconds)
    except (ValueError, TypeError):
        return '未知'
    
    if seconds < 0:
        return '未知'
    
    if seconds < 60:
        return f'{seconds}秒'
    elif seconds < 3600:
        minutes = seconds // 60
        remaining_seconds = seconds % 60
        if remaining_seconds == 0:
            return f'{minutes}分钟'
        else:
            return f'{minutes}分{remaining_seconds}秒'
    else:
        hours = seconds // 3600
        remaining_minutes = (seconds % 3600) // 60
        if remaining_minutes == 0:
            return f'{hours}小时'
        else:
            return f'{hours}小时{remaining_minutes}分钟'


def is_valid_url(url: str) -> bool:
    """验证URL格式
    
    Args:
        url: URL字符串
    
    Returns:
        是否有效
    """
    if not url or not isinstance(url, str):
        return False
    
    pattern = r'^https?://(?:[-\w.])+(?:[:\d]+)?(?:/(?:[\w/_.])*(?:\?(?:[\w&=%.])*)?(?:#(?:[\w.])*)?)?$'
    return bool(re.match(pattern, url.strip()))


def mask_sensitive_data(data: str, mask_char: str = '*', visible_chars: int = 4) -> str:
    """遮蔽敏感数据
    
    Args:
        data: 敏感数据
        mask_char: 遮蔽字符
        visible_chars: 可见字符数
    
    Returns:
        遮蔽后的数据
    """
    if not data or len(data) <= visible_chars:
        return mask_char * len(data) if data else ''
    
    visible_start = visible_chars // 2
    visible_end = visible_chars - visible_start
    
    return (
        data[:visible_start] +
        mask_char * (len(data) - visible_chars) +
        data[-visible_end:] if visible_end > 0 else ''
    )


def convert_to_bool(value: Union[str, bool, int, None]) -> bool:
    """转换为布尔值
    
    Args:
        value: 待转换的值
    
    Returns:
        布尔值
    """
    if isinstance(value, bool):
        return value
    
    if isinstance(value, str):
        return value.lower() in ('true', '1', 'yes', 'on', 'enabled')
    
    if isinstance(value, int):
        return value != 0
    
    return False


def safe_int(value: Union[str, int, float, None], default: int = 0) -> int:
    """安全转换为整数
    
    Args:
        value: 待转换的值
        default: 默认值
    
    Returns:
        整数值
    """
    try:
        if isinstance(value, str):
            value = value.strip()
            if not value:
                return default
        return int(float(value))
    except (ValueError, TypeError):
        return default


def safe_float(value: Union[str, int, float, None], default: float = 0.0) -> float:
    """安全转换为浮点数
    
    Args:
        value: 待转换的值
        default: 默认值
    
    Returns:
        浮点数值
    """
    try:
        if isinstance(value, str):
            value = value.strip()
            if not value:
                return default
        return float(value)
    except (ValueError, TypeError):
        return default


def get_client_ip(request) -> str:
    """获取客户端IP地址
    
    Args:
        request: Flask请求对象
    
    Returns:
        IP地址
    """
    # 检查代理头
    forwarded_ips = request.headers.get('X-Forwarded-For')
    if forwarded_ips:
        return forwarded_ips.split(',')[0].strip()
    
    real_ip = request.headers.get('X-Real-IP')
    if real_ip:
        return real_ip.strip()
    
    return request.remote_addr or 'unknown'


def paginate_query(query, page: int = 1, per_page: int = 20, max_per_page: int = 100):
    """分页查询
    
    Args:
        query: SQLAlchemy查询对象
        page: 页码
        per_page: 每页数量
        max_per_page: 最大每页数量
    
    Returns:
        分页对象
    """
    page = max(1, safe_int(page, 1))
    per_page = min(max_per_page, max(1, safe_int(per_page, 20)))
    
    return query.paginate(
        page=page,
        per_page=per_page,
        error_out=False
    )


def success_response(message: str = '操作成功', data=None, code: int = 200):
    """成功响应
    
    Args:
        message: 响应消息
        data: 响应数据
        code: HTTP状态码
    
    Returns:
        Flask响应对象
    """
    from flask import jsonify
    
    response_data = {
        'success': True,
        'message': message,
        'code': code
    }
    
    if data is not None:
        response_data['data'] = data
    
    return jsonify(response_data), code


def error_response(message: str = '操作失败', data=None, code: int = 400):
    """错误响应
    
    Args:
        message: 错误消息
        data: 错误数据
        code: HTTP状态码
    
    Returns:
        Flask响应对象
    """
    from flask import jsonify
    
    response_data = {
        'success': False,
        'message': message,
        'code': code
    }
    
    if data is not None:
        response_data['data'] = data
    
    return jsonify(response_data), code